package com.hxwb.sdk.manage;

import org.chainmaker.sdk.*;
import org.chainmaker.sdk.crypto.ChainMakerCryptoSuiteException;
import org.chainmaker.sdk.utils.FileUtils;
import org.junit.Assert;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.utils.Numeric;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class ChainManage {
    private static String basePath = "file:/chainmaker/config/";
    private static final String EVM_CONTRACT_FILE_PATH = "token.bin";
    private String CONTRACT_NAME;
    private static final String CONTRACT_ARGS_EVM_PARAM = "data";

    private static String GRPC_CERT_PATH_ORG1 = basePath+"crypto-config/wx-org1.chainmaker.org/ca/ca.crt";
    private static String GRPC_TLS_KEY_PATH_ORG1 = basePath+ "crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.key";
    private static String GRPC_TLS_CERT_PATH_ORG1 = basePath+ "crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.crt";
    private static String TLS_HOST_NAME1 = "consensus1.tls.wx-org1.chainmaker.org";


    private static String CHAIN_ID = "chalinked";
    private static String OPENSSL_PROVIDER = "openSSL";
    private static String TLS_NEGOTIATION = "TLS";

    static String ADMIN1_KEY_PATH = basePath+ "crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.sign.key";
    static String ADMIN1_CERT_PATH = basePath+ "crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.sign.crt";

    static String CLIENT_KEY_PATH = basePath+"crypto-config/wx-org1.chainmaker.org/user/client1/client1.sign.key";
    static String CLIENT_CERT_PATH = basePath+"crypto-config/wx-org1.chainmaker.org/user/client1/client1.sign.crt";
    static String CLIENT_CRL_PATH = "crl/client1.crl";

    static String ORG_ID1 = "wx-org1.chainmaker.org";

    static String NODE_GRPC_URL1 = "grpcs://127.0.0.1:12301";
    //static String NODE_GRPC_URL1 = "grpcs://43.129.238.191:12305";
      //static String NODE_GRPC_URL1 = "grpcs://127.0.0.1:12301";


    public ChainManage(String contractName) {
        this.CONTRACT_NAME = contractName;
    }

    ChainClient chainClient;
    ChainManager chainManager;
    User adminUser1;

    public ResponseInfo balanceOf(String address) {
        ResponseInfo responseInfo = null;
        try {
            init();
            Map<String, String> params = new HashMap<>();


            Function function = new Function("balanceOf", Arrays.asList(new Address(address)),
                    Collections.emptyList());

            String methodDataStr = FunctionEncoder.encode(function);

            String method = methodDataStr.substring(0, 10);

            params.put(CONTRACT_ARGS_EVM_PARAM, methodDataStr);


            responseInfo = chainClient.invokeContract(CONTRACT_NAME, method, params, 10000, 10000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return responseInfo;
    }

    public ResponseInfo transfer(String from, String to, long amount) {
        System.out.println(new Date()+"转账：from"+from+"to:"+to+"amount:"+amount);
        ResponseInfo responseInfo = null;
        try {
            init();
            Map<String, String> params = new HashMap<>();
            BigInteger bigInteger = BigInteger.valueOf(amount);
            Function function = new Function("transferFrom", Arrays.asList(new Address(from), new Address(to), new Uint256(bigInteger)),
                    Collections.emptyList());

            String methodDataStr = FunctionEncoder.encode(function);

            String method = methodDataStr.substring(0, 10);

            params.put(CONTRACT_ARGS_EVM_PARAM, methodDataStr);


            responseInfo = chainClient.invokeContract(CONTRACT_NAME, method, params, 10000, 10000);
        } catch (Exception e) {
            e.printStackTrace();
        }return responseInfo;
    }

    public ResponseInfo addHashCode(String address, String hashCode) {
        System.out.println(new Date()+"插入hashCode：from"+address+"hashCode:"+hashCode);
        ResponseInfo responseInfo = null;
        try {
            init();
            Map<String, String> params = new HashMap<>();
            Function function = new Function("add", Arrays.asList(new Address(address), new Utf8String("@"+hashCode)),
                    Collections.emptyList());

            String methodDataStr = FunctionEncoder.encode(function);

            String method = methodDataStr.substring(0, 10);

            params.put(CONTRACT_ARGS_EVM_PARAM, methodDataStr);


            responseInfo = chainClient.invokeContract(CONTRACT_NAME, method, params, 10000, 10000);
            System.out.println(responseInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }return responseInfo;
    }

    public ResponseInfo getHashCode(String address) {
        System.out.println(new Date()+"获取hushCodeList：from"+address);
        ResponseInfo responseInfo = null;
        try {
            init();
            Map<String, String> params = new HashMap<>();
            Function function = new Function("get", Arrays.asList(new Address(address)),
                    Collections.emptyList());

            String methodDataStr = FunctionEncoder.encode(function);

            String method = methodDataStr.substring(0, 10);

            params.put(CONTRACT_ARGS_EVM_PARAM, methodDataStr);
            responseInfo = chainClient.invokeContract(CONTRACT_NAME, method, params, 10000, 10000);
        } catch (Exception e) {
            e.printStackTrace();
        }return responseInfo;
    }

    public void init() throws IOException, ChainMakerCryptoSuiteException, ChainClientException {
        byte[][] tlsCaCerts = new byte[][]{FileUtils.getResourceFileBytes(GRPC_CERT_PATH_ORG1)};
        Node node1 = Node.builder().clientKeyBytes(FileUtils.getResourceFileBytes(GRPC_TLS_KEY_PATH_ORG1))
                .clientCertBytes(FileUtils.getResourceFileBytes(GRPC_TLS_CERT_PATH_ORG1))
                .tlsCertBytes(tlsCaCerts)
                .hostname(TLS_HOST_NAME1).grpcUrl(NODE_GRPC_URL1)
                .sslProvider(OPENSSL_PROVIDER).negotiationType(TLS_NEGOTIATION).build();

        chainManager = ChainManager.getInstance();
        chainClient = chainManager.getChainClient(CHAIN_ID);
        User clientUser = new User(ORG_ID1, FileUtils.getResourceFileBytes(CLIENT_KEY_PATH),
                FileUtils.getResourceFileBytes(CLIENT_CERT_PATH));
        if (chainClient == null) {
            //            chainClient = chainManager.createChainClient(CHAIN_ID, clientUser, new Node[]{node1, node2, node3});
            chainClient = chainManager.createChainClient(CHAIN_ID, clientUser, new Node[]{node1});
        }
        adminUser1 = new User(ORG_ID1, FileUtils.getResourceFileBytes(ADMIN1_KEY_PATH),
                FileUtils.getResourceFileBytes(ADMIN1_CERT_PATH));
    }
}
